package com.whosly.rapid.lang.thread.executor;

import com.whosly.rapid.lang.thread.AsyncLoadCallable;
import com.whosly.rapid.lang.thread.AsyncLoadFuture;
import com.whosly.rapid.lang.thread.factory.NamedThreadFactory;

import java.util.concurrent.*;

/**
 * 线程池实例化工具
 */
public class AsyncLoadExecutors {
    private final Object object = new Object();

    public static final int DEFAULT_POOL_SIZE = 20;
    public static final int DEFAULT_ACCEPT_COUNT = 100;
    public static final HandleMode DEFAULT_MODE = HandleMode.REJECT;
    private int poolSize;
    /**
     * 等待队列长度，避免无限制提交请求
     */
    private int acceptCount;
    /**
     * 默认为拒绝服务，用于控制accept队列满了以后的处理方式
     */
    private HandleMode mode;
    private MonitorThreadPoolExecutor pool;
    private volatile boolean isInit = false;

    enum HandleMode {
        /**
         * 拒绝
         */
        REJECT,
        /**
         * CALLERRUN
         */
        CALLERRUN;
    }

    public AsyncLoadExecutors() {
        this(DEFAULT_POOL_SIZE, DEFAULT_ACCEPT_COUNT, DEFAULT_MODE);
    }

    public AsyncLoadExecutors(int poolSize) {
        this(poolSize, DEFAULT_ACCEPT_COUNT, DEFAULT_MODE);
    }

    public AsyncLoadExecutors(int poolSize, int acceptCount) {
        this(poolSize, acceptCount, DEFAULT_MODE);
    }

    public AsyncLoadExecutors(int poolSize, int acceptCount, HandleMode mode) {
        this.poolSize = poolSize;
        this.acceptCount = acceptCount;
        this.mode = mode;
    }

    /**
     * 初始化, 并且一个本实例只会初始化一次
     */
    public void initital() {
        if (!isInit) {
            synchronized (object){
                if (!isInit) {
                    RejectedExecutionHandler handler = getHandler(mode);
                    BlockingQueue<Runnable> queue = getBlockingQueue(acceptCount, mode);
                    // 构造pool池
                    this.pool = new MonitorThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue,
                            new NamedThreadFactory("asyncload-lang-pool"), handler);

                    isInit = true;
                }
            }
        }
    }

    public void destory() {
        if (isInit && pool != null) {
            pool.shutdown();
            pool = null;

            isInit = false;
        }
    }

    public <T> AsyncLoadFuture<T> submit(AsyncLoadCallable<T> task) {
        return pool.submit(task);
    }

    // ==================== help method ===========================

    private BlockingQueue<Runnable> getBlockingQueue(int acceptCount, HandleMode mode) {
        if (acceptCount < 0) {
            return new LinkedBlockingQueue<>();
        } else if (acceptCount == 0) {
            return new ArrayBlockingQueue<>(1);
        } else {
            return new ArrayBlockingQueue<>(acceptCount);
        }
    }

    private RejectedExecutionHandler getHandler(HandleMode mode) {
        return HandleMode.REJECT == mode ? new MonitorThreadPoolExecutor.AbortPolicy() : new MonitorThreadPoolExecutor.CallerRunsPolicy();
    }

    // ====================== setter / getter ==========================

    public void setPoolSize(int poolSize) {
        this.poolSize = poolSize;
    }

    public void setAcceptCount(int acceptCount) {
        this.acceptCount = acceptCount;
    }

    public void setMode(HandleMode mode) {
        this.mode = mode;
    }

    public void setMode(String mode) {
        this.mode = HandleMode.valueOf(mode);
    }

    // ======================= help method ==========================

    @Override
    public String toString() {
        return "AsyncLoadExecutors [ poolSize=" + poolSize + ", acceptCount=" + acceptCount + ", mode=" + mode + "]";
    }
}
